﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Windows.Devices.Geolocation;
using System.Device.Location;
using System.Windows.Media;
using Microsoft.Phone.Maps.Controls;
using System.Windows.Media.Imaging;
using System.Threading;
using System.ComponentModel;
using Puddy.Models;
using Puddy.UserControls;
using System.Diagnostics;
using Puddy.Utils;
using System.Collections.ObjectModel;
using Puddy.ViewModels;
using System.Windows.Threading;




namespace Puddy
{
    public partial class AddLocationPage : PhoneApplicationPage
    {
        Place myPlace;
        Place currentSelectedPlace;

        //to flag whether user input on textbox location  or textbox location is assigned text
        bool isLocationTextIsAssign = false;
        String addressHasJustSearch = "";

        private  DispatcherTimer timerSearchLocation = new DispatcherTimer();
        MapLayer layerPushPin = new MapLayer();
        MapOverlay overlayForMyLocation = null;
        MapOverlay overlayUserTouched = null;

        ObservableCollection<us_SearchResultItem> ListSearchPlace;

        public AddLocationPage()
        {
            InitializeComponent();

            myPlace = new Place();

            map.Layers.Add(layerPushPin);

            //set current location quickly ->> improve performance
            if (App.myCurrentLocation != null)
            {
                myPlace.Longitude = App.myCurrentLocation.Longitude;
                myPlace.Lattitude = App.myCurrentLocation.Latitude;

                AddPushPinForMyCurrentLocation(App.myCurrentLocation.Latitude, App.myCurrentLocation.Longitude);
                map.SetView(new GeoCoordinate(App.myCurrentLocation.Latitude, App.myCurrentLocation.Longitude, 200), 11);
            }else
                getMyLocation();

            timerSearchLocation.Tick += timerSearchLocation_Tick;

            ListSearchPlace = new ObservableCollection<us_SearchResultItem>();
            lls_resultLocation.ItemsSource = ListSearchPlace;


        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (App.RunningAlarm)
            {
                this.NavigationService.Navigate(new Uri("/AlarmPage.xaml", UriKind.Relative));
            }

            if (App.ShouldShowMessTurnOffLocation)
            {
                App.ShouldShowMessTurnOffLocation = false;
                MessageBox.Show(Constants.MES_TURN_OFF_LOCATION);

            }
        }

        protected override void OnRemovedFromJournal(System.Windows.Navigation.JournalEntryRemovedEventArgs e)
        {
            timerSearchLocation.Stop();
            timerSearchLocation.Tick -= timerSearchLocation_Tick;
            timerSearchLocation = null;
        }

        /// <summary>
        /// Add single push pin on map
        /// </summary>
        /// <param name="pin"></param>
        public void AddPushPin(double Lattitude, double Longitude)
        {
            if (overlayUserTouched == null)
            {
                overlayUserTouched = new MapOverlay();                
                Image image = new Image();
                image.Source = new BitmapImage(new Uri(@"/Assets/Location selection.png", UriKind.Relative));
                overlayUserTouched.Content = image;
                layerPushPin.Add(overlayUserTouched);
            }

            overlayUserTouched.GeoCoordinate = new GeoCoordinate(Lattitude, Longitude);
            
        }

        public void AddPushPinForMyCurrentLocation(double Lattitude, double Longitude)
        {
            if (overlayForMyLocation == null)
            {
                overlayForMyLocation = new MapOverlay();                
                Image image = new Image();
                image.Source = new BitmapImage(new Uri(@"/Assets/person.png", UriKind.Relative));
                overlayForMyLocation.Content = image;
                layerPushPin.Add(overlayForMyLocation);
            }

            overlayForMyLocation.GeoCoordinate = new GeoCoordinate(Lattitude, Longitude);
            
        }

        private async void getMyLocation()
        {
            Geolocator geolocator = new Geolocator();
            geolocator.DesiredAccuracyInMeters = 50;

            try
            {
                Geoposition geoposition = await geolocator.GetGeopositionAsync(
                    maximumAge: TimeSpan.FromMinutes(5),
                    timeout: TimeSpan.FromSeconds(10)
                    );
                App.myCurrentLocation = geoposition.Coordinate.ToGeoCoordinate();

                myPlace.Longitude = geoposition.Coordinate.Longitude;
                myPlace.Lattitude = geoposition.Coordinate.Latitude;

                AddPushPinForMyCurrentLocation(geoposition.Coordinate.Latitude, geoposition.Coordinate.Longitude);
                map.SetView(new GeoCoordinate(geoposition.Coordinate.Latitude, geoposition.Coordinate.Longitude, 200), 11);


            }
            catch (Exception ex)
            {
                if ((uint)ex.HResult == 0x80004004)
                {
                    // the application does not have the right capability or the location master switch is off
                    //MessageBox.Show("GPS is disabled, this may cause the Puddy app to fail.");
                    //toast.Show("GPS is disabled, this may cause the Puddy app to fail.");
                    if (isClickBtnGetLocation)
                        MessageBox.Show(Constants.MES_TURN_OFF_LOCATION);
                }
                //else
                {
                    // something else happened acquring the location
                }
            }
        }


        private void showWaiting()
        {
            pg_waiting.Visibility = Visibility.Visible;
        }

        private void hideWaiting()
        {
            pg_waiting.Visibility = Visibility.Collapsed;
        }
   
        private void tb_location_SelectionChanged(object sender, RoutedEventArgs e)
        {
            if (!isLocationTextIsAssign)
            {
                if (tb_location.MyText != ""){
                    if (tb_location.MyText != addressHasJustSearch)
                        searchLocation();
                }
                else
                {
                    map.Visibility = Visibility.Visible;
                    lls_resultLocation.Visibility = Visibility.Collapsed;

                    addressHasJustSearch = "";
                }
            }
            isLocationTextIsAssign = false;
        }

        private void searchLocation()
        {
            timerSearchLocation.Stop();
            timerSearchLocation.Interval = new TimeSpan(0, 0, 3);
            timerSearchLocation.Start();

        }

        

        void timerSearchLocation_Tick(object sender, EventArgs e)
        {
            startSearch();
        }

        /// <summary>
        /// when start search flagCheckSearchFinish = 0;
        /// google search complete flagCheckSearchFinish + 1
        /// fourquare search complete flagCheckSearchFinish + 1
        /// </summary>
        
        int flagCheckSearchFinish = 0;

        private void startSearch()
        {
            if (tb_location.MyText != "")
            {
                showWaiting();
                timerSearchLocation.Stop();

                flagCheckSearchFinish = 0;
                hasData = false;
                ListSearchPlace.Clear();

                addressHasJustSearch = tb_location.MyText;

                String str_lat, str_lng;
                if (myPlace == null)
                {
                    str_lat = "0.0";
                    str_lng = "0.0";
                }
                else
                {
                    str_lat = myPlace.Lattitude.ToString();
                    str_lng = myPlace.Longitude.ToString();
                }
                FoursquareServiceHandler foursquareService = new FoursquareServiceHandler();
                foursquareService.searchByFoursquare(tb_location.MyText, myPlace.Lattitude.ToString(), myPlace.Longitude.ToString());
                foursquareService.OnGetPlace += fourSquareService_OnGetPlace;

                GoogleServiceHandler service = new GoogleServiceHandler();
                service.GetPlaceByKeyWord(tb_location.MyText);
                service.OnGetPlace += googleService_OnGetPlace;
            }
            
        }

        bool hasData = false;

        void googleService_OnGetPlace(List<Place> places)
        {
            
            if (places != null)
            {
                if (places.Count > 0)
                    hasData = true;
                addPlaces(places, Constants.GOOGLE_DATA);
            }
            else
            {
                //error
            }

            flagCheckSearchFinish++;
            if (flagCheckSearchFinish >= 2)
            {
                hideWaiting();
                if (!hasData)
                    toast.Show("Search no result");
            }
            
        }

        void fourSquareService_OnGetPlace(List<Place> places)
        {
            
            if (places != null)
            {
                if (places.Count > 0)
                    hasData = true;
                addPlaces(places, Constants.FOURSQUARE_DATA);
            }
            else
            {
                //error
            }

            flagCheckSearchFinish++;
            if (flagCheckSearchFinish >= 2)
            {
                hideWaiting();
                if (!hasData)
                    toast.Show("Search no result");
            }
        }

         void addPlaces(List<Place> places, int typeDataFrom)
        {
            flagCheckSearchFinish++;
            if (places.Count > 0)
            {
                map.Visibility = Visibility.Collapsed;
                lls_resultLocation.Visibility = Visibility.Visible;

                //remove all place by typeDataFrom to add new places
                //RemovePlaces(typeDataFrom);

                foreach (Place place in places)
                {
                    us_SearchResultItem item = new us_SearchResultItem();
                    if (typeDataFrom == Constants.GOOGLE_DATA)
                        item.setGoogleTyle();
                    else if (typeDataFrom == Constants.FOURSQUARE_DATA)
                        item.setFoursquareTyle();

                    item.setAddress(place.Address);
                    item.Tag = place;

                    try
                    {
                        Dispatcher.BeginInvoke(() =>
                        {
                            ListSearchPlace.Add(item);
                        });
                    }
                    catch (System.Exception ex)
                    {
                        //test
                        MessageBox.Show("update UI error");
                    }
                     
                }
            }
            else
            {
                

                if (lls_resultLocation.ItemsSource != null && lls_resultLocation.ItemsSource.Count == 0)
                {
                    map.Visibility = Visibility.Visible;
                    lls_resultLocation.Visibility = Visibility.Collapsed;
                }
            }

        }

        void RemovePlaces(int  typeDataFrom)
        {
            if (lls_resultLocation.ItemsSource != null)
            {
                int i;
                for (i = lls_resultLocation.ItemsSource.Count - 1; i >= 0; i-- )
                {
                    us_SearchResultItem item = (lls_resultLocation.ItemsSource as ObservableCollection<us_SearchResultItem>).ElementAt(i);
                    if (item.TypeDataFrom == typeDataFrom)
                    {
                        lls_resultLocation.ItemsSource.Remove(item);
                    }
                }
            }
        }

        private void lls_resultLocation_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            try
            {
                if (lls_resultLocation.SelectedItem == null)
                    return;

                Place place = (lls_resultLocation.SelectedItem as us_SearchResultItem).Tag as Place;
                tb_location.MyText = place.Address;
                isLocationTextIsAssign = true;
                addressHasJustSearch = place.Address;

                AddPushPin(place.Lattitude, place.Longitude);
                map.SetView(new GeoCoordinate(place.Lattitude, place.Longitude, 200), 9);

                currentSelectedPlace = place;

                map.Visibility = Visibility.Visible;
                lls_resultLocation.Visibility = Visibility.Collapsed;
            }
            catch ( Exception ex){
                MessageBox.Show(ex.Message);
            }
            

        }

        

        private void map_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            Point p = e.GetPosition(this.map);
            GeoCoordinate geo = new GeoCoordinate();
            geo = map.ConvertViewportPointToGeoCoordinate(p);

            showWaiting();

            GoogleServiceHandler service = new GoogleServiceHandler();
            service.GetPlaceByLatLng(geo.Latitude, geo.Longitude);
            service.OnGetGeocodingLocation += googleService_OnGetPlaceByLatLng;

            AddPushPin(geo.Latitude, geo.Longitude);
        }

        void googleService_OnGetPlaceByLatLng(int count, String address, double lat, double lng)
        {
            hideWaiting();

            if (count > 0)
            {
                tb_location.MyText = address;
                isLocationTextIsAssign = true;
                addressHasJustSearch = address;

                currentSelectedPlace = new Place();
                currentSelectedPlace.Address = address;
                currentSelectedPlace.Lattitude = lat;
                currentSelectedPlace.Longitude = lng;
            }
            

        }

        #region event

        private void tb_name_TextChanged(object sender, TextChangedEventArgs e)
        {

        }

        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            
            if (tb_location.MyText == "" || tb_name.MyText == "")
            {
                toast.Show("Location name or address is empty!");
                return;
            }
            if (currentSelectedPlace == null)
            {
                toast.Show("Please select location!");
                return;
            }

            LocationViewModel locationVC = new LocationViewModel(tb_name.MyText, tb_location.MyText, Constants.ON_STATE);
            locationVC.Latitude = currentSelectedPlace.Lattitude;
            locationVC.Longitude = currentSelectedPlace.Longitude;
            App.ViewModel.LocationList.Add(locationVC);
            App.ViewModel.ListItemStateOn.Add(locationVC);

            //fix bug sometime could not load data 
            RestoreData.CreateJsonLocationList(App.ViewModel.LocationList);

            if (App.ViewModel.ListItemStateOn.Count == 1)
            {
                App.turnOnTrackLocation();
            }
            else
            {
                App.recheckLocation();
            }

            NavigationService.GoBack();
        }

        private void btnRemove_Click(object sender, RoutedEventArgs e)
        {
            NavigationService.GoBack();
        }

        bool isClickBtnGetLocation = false;
        private void btnGetLocation_Click(object sender, RoutedEventArgs e)
        {
            lls_resultLocation.Visibility = Visibility.Collapsed;
            map.Visibility = Visibility.Visible;

            isClickBtnGetLocation = true;
            getMyLocation();
        }

        private void tb_name_SelectionChanged(object sender, RoutedEventArgs e)
        {

        }

        bool isGotFocus = false;
        private void tb_location_GotFocus(object sender, System.Windows.RoutedEventArgs e)
        {
        	// TODO: Add event handler implementation here.
            isGotFocus = true;
        }


        private void tb_location_LostFocus(object sender, System.Windows.RoutedEventArgs e)
        {
            // TODO: Add event handler implementation here.
            if (isGotFocus)
            {
                if (!isLocationTextIsAssign)
                {
                    if (tb_location.MyText != "" && tb_location.MyText != addressHasJustSearch)
                    {
                        startSearch();
                    }
                        
                    
                }
            }

            isGotFocus = false;
        }

        #endregion
    }
        
}